package com.bw.app.data;

import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 达摩盘宠物特征数据生成器
 * 工单编号：大数据-用户画像-13-达摩盘宠物特征
 * 功能：生成符合宠物类型标签、宠物年龄阶段标签计算逻辑的用户行为数据
 * 数据覆盖：用户近180天浏览/收藏/加购/购买行为，支持猫狗及多类小宠的特征计算
 */
public class DmpPetFeatureDataGenerator {
    // 1. 行为类型及权重配置（遵循工单：购买5、加购3、收藏2、浏览1）
    private static final Map<String, Integer> BEHAVIOR_WEIGHT = new HashMap<>();
    // 2. 宠物类型-类目映射配置（遵循工单类目规则，含通用类目标记）
    private static final List<Map<String, Object>> PET_CATEGORY_CONFIG = new ArrayList<>();
    // 3. 猫狗年龄阶段-关键词映射配置（结合图片核心类目及工单规则）
    private static final List<Map<String, Object>> PET_AGE_CONFIG = new ArrayList<>();
    // 4. 时间窗口配置（工单要求：近180天行为数据）
    private static final int TIME_WINDOW_DAYS = 180;
    // 5. 标签判定阈值（工单要求：宠物类型≥10分，年龄强相关≥20分、弱相关10-20分）
    private static final int PET_TYPE_THRESHOLD = 10;
    private static final int PET_AGE_STRONG_THRESHOLD = 20;
    private static final int PET_AGE_WEAK_THRESHOLD = 10;

    static {
        // 初始化行为权重（工单2.行为权重规则）
        BEHAVIOR_WEIGHT.put("购买", 5);
        BEHAVIOR_WEIGHT.put("加购", 3);
        BEHAVIOR_WEIGHT.put("收藏", 2);
        BEHAVIOR_WEIGHT.put("浏览", 1);

        // 初始化宠物类型-类目映射（工单1.类目映射规则）
        // 4.1 狗狗专属类目
        addPetCategoryConfig("狗", "狗狗", false);
        addPetCategoryConfig("狗", "狗零食", false);
        addPetCategoryConfig("狗", "犬主粮", false);
        // 4.2 猫咪专属类目
        addPetCategoryConfig("猫", "猫咪", false);
        addPetCategoryConfig("猫", "猫零食", false);
        addPetCategoryConfig("猫", "猫主粮", false);
        // 4.3 通用类目（猫/狗共享，按50%权重分配）
        addPetCategoryConfig("通用", "猫/狗玩具", true);
        addPetCategoryConfig("通用", "猫/狗保健品", true);
        addPetCategoryConfig("通用", "猫/狗美容清洁用品", true);
        addPetCategoryConfig("通用", "猫/狗日用品", true);
        addPetCategoryConfig("通用", "猫/狗医疗用品（非药品）", true);
        // 4.4 小宠类目（仓鼠、龙猫等）
        addPetCategoryConfig("仓鼠", "仓鼠类及其它小宠>仓鼠", false);
        addPetCategoryConfig("仓鼠", "仓鼠类及其它小宠>饲料/零食", false);
        addPetCategoryConfig("仓鼠", "仓鼠类及其它小宠>医疗/保健品（新）", false);
        addPetCategoryConfig("龙猫", "仓鼠类及其它小宠>龙猫", false);
        addPetCategoryConfig("宠物狐狸", "仓鼠类及其它小宠>宠物狐狸", false);
        addPetCategoryConfig("宠物貂", "仓鼠类及其它小宠>宠物貂", false);
        addPetCategoryConfig("香猪", "仓鼠类及其它小宠>香猪", false);
        addPetCategoryConfig("豚鼠", "仓鼠类及其它小宠>豚鼠", false);
        // 4.5 其他宠物类目
        addPetCategoryConfig("鸟类", "鸟类及用品>鸟粮", false);
        addPetCategoryConfig("鸟类", "鸟类及用品>鸟笼", false);
        addPetCategoryConfig("爬虫/鸣虫", "爬虫/鸣虫及其用品>爬虫饲料", false);
        addPetCategoryConfig("水族", "水族世界>鱼缸", false);
        addPetCategoryConfig("水族", "水族世界>鱼粮", false);
        addPetCategoryConfig("兔类", "兔类及其用品>兔粮", false);
        addPetCategoryConfig("马类", "马类及其用品>马饲料", false);

        // 初始化猫狗年龄阶段-关键词配置（结合图片核心类目及工单规则）
        // 5.1 狗狗年龄阶段
        addPetAgeConfig("狗", "幼年(0-1岁)", Arrays.asList("幼犬粮", "磨牙棒", "宠物训练", "疫苗套餐"));
        addPetAgeConfig("狗", "成年(1-7岁)", Arrays.asList("成犬粮", "常规零食", "日常护理", "配种服务"));
        addPetAgeConfig("狗", "老年(7岁+)", Arrays.asList("老年保健粮", "关节护理", "医疗护理", "临终关怀"));
        // 5.2 猫咪年龄阶段
        addPetAgeConfig("猫", "幼年(0-1岁)", Arrays.asList("幼猫粮", "猫奶粉", "猫砂训练", "疫苗"));
        addPetAgeConfig("猫", "成年(1-12岁)", Arrays.asList("成猫粮", "常规罐头", "猫爬架", "绝育套餐"));
        addPetAgeConfig("猫", "老年(12岁+)", Arrays.asList("肾处方粮", "老年护理", "安乐死咨询"));
    }

    /**
     * 新增宠物类型-类目配置
     * @param petType 宠物类型（如狗、猫、通用）
     * @param category 完整类目路径
     * @param isCommon 是否为通用类目（猫/狗共享）
     */
    private static void addPetCategoryConfig(String petType, String category, boolean isCommon) {
        Map<String, Object> config = new HashMap<>();
        config.put("petType", petType);
        config.put("category", category);
        config.put("isCommon", isCommon);
        PET_CATEGORY_CONFIG.add(config);
    }

    /**
     * 新增宠物年龄阶段-关键词配置
     * @param petType 宠物类型（仅狗/猫）
     * @param ageStage 年龄阶段（如幼年(0-1岁)）
     * @param keywords 关联关键词列表
     */
    private static void addPetAgeConfig(String petType, String ageStage, List<String> keywords) {
        Map<String, Object> config = new HashMap<>();
        config.put("petType", petType);
        config.put("ageStage", ageStage);
        config.put("keywords", keywords);
        PET_AGE_CONFIG.add(config);
    }

    /**
     * 计算时间衰减因子（工单规则：距离当前时间每30天权重×0.9）
     * @param behaviorDate 行为发生时间
     * @param currentDate 当前时间（计算基准）
     * @return 时间衰减系数
     */
    private static double getTimeDecayFactor(LocalDateTime behaviorDate, LocalDateTime currentDate) {
        long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(behaviorDate, currentDate);
        // 超过180天的行为数据过滤（工单时间窗口要求）
        if (daysDiff > TIME_WINDOW_DAYS) {
            return 0.0;
        }
        // 每30天衰减一次，衰减系数=0.9^(天数差/30)
        int decayTimes = (int) (daysDiff / 30);
        return Math.pow(0.9, decayTimes);
    }

    /**
     * 计算连续购买衰减系数（工单规则：同商品重复购买，第二次起权重×0.7递减）
     * @param purchaseCount 该商品的累计购买次数（当前行为为第N次）
     * @return 连续购买衰减系数
     */
    private static double getRepeatPurchaseFactor(int purchaseCount) {
        if (purchaseCount <= 1) {
            return 1.0;
        }
        // 第2次×0.7，第3次×0.7²，以此类推
        return Math.pow(0.7, purchaseCount - 1);
    }

    /**
     * 匹配商品对应的宠物年龄阶段（基于商品标题关键词）
     * @param productTitle 商品标题
     * @param petType 宠物类型（仅狗/猫）
     * @return 匹配到的年龄阶段列表（可能多个）
     */
    private static List<String> matchPetAgeStage(String productTitle, String petType) {
        List<String> matchedStages = new ArrayList<>();
        for (Map<String, Object> ageConfig : PET_AGE_CONFIG) {
            if (petType.equals(ageConfig.get("petType"))) {
                List<String> keywords = (List<String>) ageConfig.get("keywords");
                // 标题包含任意关键词则匹配该年龄阶段
                for (String keyword : keywords) {
                    if (productTitle.contains(keyword)) {
                        matchedStages.add((String) ageConfig.get("ageStage"));
                        break;
                    }
                }
            }
        }
        // 无匹配时返回空列表
        return matchedStages;
    }

    /**
     * 生成用户ID（格式：U+8位数字，从10000000开始递增）
     * @param index 用户序号
     * @return 唯一用户ID
     */
    private static String generateUserId(int index) {
        return "U" + (10000000 + index);
    }

    /**
     * 生成商品标题（基于类目和年龄阶段关键词）
     * @param category 商品类目
     * @param ageStage 年龄阶段（可为空，非猫狗类目无需年龄）
     * @return 商品标题
     */
    private static String generateProductTitle(String category, String ageStage) {
        Random random = new Random();
        List<String> prefixes = Arrays.asList("优质", "新品", "热销", "特惠");
        String prefix = prefixes.get(random.nextInt(prefixes.size()));

        // 提取类目名称（处理含>和不含>的情况）
        String categoryName = category;
        if (category.contains(">")) {
            categoryName = category.split(">")[1];
        }

        // 若有年龄阶段，拼接年龄相关关键词
        if (ageStage != null && !ageStage.isEmpty()) {
            String ageKeyword = ageStage.contains("幼年") ? "幼宠专用" :
                    ageStage.contains("成年") ? "成宠专用" : "老年专用";
            return String.format("%s %s %s", prefix, categoryName, ageKeyword);
        }
        // 非猫狗类目直接生成标题
        return String.format("%s %s", prefix, categoryName);
    }

    /**
     * 生成行为时间（在近180天内随机）
     * @param currentDate 当前时间（计算基准）
     * @param random 随机数实例
     * @return 行为发生时间
     */
    private static LocalDateTime generateBehaviorTime(LocalDateTime currentDate, Random random) {
        int daysAgo = random.nextInt(TIME_WINDOW_DAYS + 1); // 0-TIME_WINDOW_DAYS天前
        return currentDate.minusDays(daysAgo)
                .withHour(random.nextInt(24))
                .withMinute(random.nextInt(60))
                .withSecond(random.nextInt(60));
    }

    /**
     * 判定用户宠物类型标签（遵循工单3.标签判定规则）
     * @param userPetScores 用户各宠物类型的累计得分
     * @return 达标宠物类型列表（单类型≥10分）
     */
    private static List<String> determinePetTypeTags(Map<String, Double> userPetScores) {
        List<String> petTags = new ArrayList<>();
        for (Map.Entry<String, Double> entry : userPetScores.entrySet()) {
            // 排除通用类型，仅统计具体宠物类型
            if (!"通用".equals(entry.getKey()) && entry.getValue() >= PET_TYPE_THRESHOLD) {
                petTags.add(entry.getKey());
            }
        }
        return petTags;
    }

    /**
     * 判定用户宠物年龄阶段标签（遵循工单规则）
     * @param userPetAgeScores 用户各宠物类型-年龄阶段的累计得分
     * @return 达标年龄标签列表（格式：{宠物类型}-{年龄阶段}）
     */
    private static List<String> determinePetAgeTags(Map<String, Map<String, Double>> userPetAgeScores) {
        List<String> ageTags = new ArrayList<>();

        for (Map.Entry<String, Map<String, Double>> petEntry : userPetAgeScores.entrySet()) {
            String petType = petEntry.getKey();
            Map<String, Double> ageScores = petEntry.getValue();

            if (ageScores.isEmpty()) {
                continue;
            }

            // 1. 筛选所有≥10分的阶段
            List<Map.Entry<String, Double>> validEntries = new ArrayList<>();
            for (Map.Entry<String, Double> ageEntry : ageScores.entrySet()) {
                if (ageEntry.getValue() >= PET_AGE_WEAK_THRESHOLD) {
                    validEntries.add(ageEntry);
                }
            }

            if (validEntries.isEmpty()) {
                continue;
            }

            // 2. 按得分降序排序
            validEntries.sort((e1, e2) -> Double.compare(e2.getValue(), e1.getValue()));

            // 3. 保留强相关（≥20分）或前两名且≥10分的阶段
            double maxScore = validEntries.get(0).getValue();
            for (Map.Entry<String, Double> entry : validEntries) {
                boolean isStrong = entry.getValue() >= PET_AGE_STRONG_THRESHOLD;
                boolean isTopTwo = validEntries.indexOf(entry) < 2;
                if (isStrong || isTopTwo) {
                    ageTags.add(String.format("%s-%s", petType, entry.getKey()));
                }
            }
        }

        return ageTags;
    }

    /**
     * 生成达摩盘宠物特征数据
     * @param numRecords 生成数据条数
     * @param csvFilePath 输出CSV文件路径
     */
    public static void generateDmpPetFeatureData(int numRecords, String csvFilePath) {
        // 计算基准时间：当前时间（示例用2025-05-01，与工单创建时间匹配）
        LocalDateTime currentDate = LocalDateTime.of(2025, 5, 1, 0, 0, 0);
        Random random = new Random();

        // 存储原始行为数据
        List<Map<String, Object>> behaviorData = new ArrayList<>();
        // 统计用户-商品购买次数（用于连续购买衰减计算）
        Map<String, Map<String, Integer>> userProductPurchaseCount = new HashMap<>();

        // 第一步：生成原始行为数据
        for (int i = 0; i < numRecords; i++) {
            // 1. 基础字段生成
            String userId = generateUserId(i);
            LocalDateTime behaviorTime = generateBehaviorTime(currentDate, random);
            String behaviorType = new ArrayList<>(BEHAVIOR_WEIGHT.keySet()).get(random.nextInt(BEHAVIOR_WEIGHT.size()));
            Map<String, Object> categoryConfig = PET_CATEGORY_CONFIG.get(random.nextInt(PET_CATEGORY_CONFIG.size()));

            // 2. 类目相关字段
            String petType = (String) categoryConfig.get("petType");
            String category = (String) categoryConfig.get("category");
            boolean isCommon = (boolean) categoryConfig.get("isCommon");

            // 3. 商品标题生成（仅猫狗类目关联年龄阶段）
            String ageStage = null;
            if (("狗".equals(petType) || "猫".equals(petType))) {
                List<Map<String, Object>> petAgeConfigs = PET_AGE_CONFIG.stream()
                        .filter(cfg -> petType.equals(cfg.get("petType")))
                        .collect(Collectors.toList());
                ageStage = (String) petAgeConfigs.get(random.nextInt(petAgeConfigs.size())).get("ageStage");
            }
            String productTitle = generateProductTitle(category, ageStage);

            // 4. 行为权重计算（基础权重×时间衰减×连续购买衰减）
            int baseWeight = BEHAVIOR_WEIGHT.get(behaviorType);
            double timeDecay = getTimeDecayFactor(behaviorTime, currentDate);

            // 连续购买衰减（仅购买行为需计算）
            double repeatPurchaseDecay = 1.0;
            if ("购买".equals(behaviorType)) {
                // 初始化用户-商品购买次数统计
                userProductPurchaseCount.computeIfAbsent(userId, k -> new HashMap<>());
                Map<String, Integer> productCount = userProductPurchaseCount.get(userId);
                String productKey = category + "-" + productTitle; // 简化商品唯一标识
                int count = productCount.getOrDefault(productKey, 0) + 1;
                productCount.put(productKey, count);
                repeatPurchaseDecay = getRepeatPurchaseFactor(count);
            }

            // 最终行为权重（保留2位小数）
            double finalBehaviorWeight = Math.round(baseWeight * timeDecay * repeatPurchaseDecay * 100.0) / 100.0;

            // 5. 宠物类型得分计算（通用类目分拆给猫狗）
            Map<String, Double> petScores = new HashMap<>();
            if (isCommon) {
                // 通用类目：猫、狗各得50%权重
                double commonScore = finalBehaviorWeight * 0.5;
                petScores.put("猫", commonScore);
                petScores.put("狗", commonScore);
            } else {
                // 专属类目：直接计入对应宠物类型
                petScores.put(petType, finalBehaviorWeight);
            }

            // 6. 宠物年龄阶段得分计算（仅猫狗类目）
            Map<String, Double> petAgeScores = new HashMap<>();
            if (("狗".equals(petType) || "猫".equals(petType)) && ageStage != null) {
                List<String> matchedAges = matchPetAgeStage(productTitle, petType);
                for (String matchedAge : matchedAges) {
                    petAgeScores.put(String.format("%s-%s", petType, matchedAge), finalBehaviorWeight);
                }
            }

            // 7. 组装单条行为数据
            Map<String, Object> behaviorRecord = new HashMap<>();
            behaviorRecord.put("user_id", userId);
            behaviorRecord.put("behavior_type", behaviorType);
            behaviorRecord.put("behavior_time", behaviorTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            behaviorRecord.put("product_category", category);
            behaviorRecord.put("product_title", productTitle);
            behaviorRecord.put("base_behavior_weight", baseWeight);
            behaviorRecord.put("time_decay_factor", Math.round(timeDecay * 100.0) / 100.0);
            behaviorRecord.put("repeat_purchase_decay", Math.round(repeatPurchaseDecay * 100.0) / 100.0);
            behaviorRecord.put("final_behavior_weight", finalBehaviorWeight);
            behaviorRecord.put("pet_type_scores", petScores); // 宠物类型得分Map
            behaviorRecord.put("pet_age_scores", petAgeScores); // 宠物年龄得分Map

            behaviorData.add(behaviorRecord);
        }

        // 第二步：聚合用户维度得分
        // 2.1 聚合用户各宠物类型总得分
        Map<String, Map<String, Double>> userPetTotalScores = new HashMap<>();
        // 2.2 聚合用户各宠物年龄阶段总得分
        Map<String, Map<String, Double>> userPetAgeTotalScores = new HashMap<>();

        for (Map<String, Object> record : behaviorData) {
            String userId = (String) record.get("user_id");
            Map<String, Double> petScores = (Map<String, Double>) record.get("pet_type_scores");
            Map<String, Double> petAgeScores = (Map<String, Double>) record.get("pet_age_scores");

            // 聚合宠物类型得分
            userPetTotalScores.computeIfAbsent(userId, k -> new HashMap<>());
            Map<String, Double> userPetScores = userPetTotalScores.get(userId);
            for (Map.Entry<String, Double> entry : petScores.entrySet()) {
                userPetScores.put(entry.getKey(), userPetScores.getOrDefault(entry.getKey(), 0.0) + entry.getValue());
            }

            // 聚合宠物年龄阶段得分
            userPetAgeTotalScores.computeIfAbsent(userId, k -> new HashMap<>());
            Map<String, Double> userAgeScores = userPetAgeTotalScores.get(userId);
            for (Map.Entry<String, Double> entry : petAgeScores.entrySet()) {
                userAgeScores.put(entry.getKey(), userAgeScores.getOrDefault(entry.getKey(), 0.0) + entry.getValue());
            }
        }

        // 第三步：判定用户标签并写入CSV
        try (FileWriter writer = new FileWriter(csvFilePath)) {
            // 写入CSV表头
            writer.write("user_id,behavior_type,behavior_time,product_category,product_title,base_behavior_weight,time_decay_factor,repeat_purchase_decay,final_behavior_weight,pet_type_total_scores,pet_type_tags,pet_age_total_scores,pet_age_tags\n");

            for (Map<String, Object> record : behaviorData) {
                String userId = (String) record.get("user_id");

                // 1. 获取用户宠物类型总得分及标签
                Map<String, Double> userPetScores = userPetTotalScores.getOrDefault(userId, new HashMap<>());
                List<String> petTypeTags = determinePetTypeTags(userPetScores);
                // 格式化得分（宠物类型:得分）
                String petTypeScoreStr = userPetScores.entrySet().stream()
                        .map(entry -> String.format("%s:%.2f", entry.getKey(), entry.getValue()))
                        .reduce((a, b) -> a + "|" + b)
                        .orElse("");
                // 格式化标签（逗号分隔）
                String petTypeTagStr = String.join(",", petTypeTags);

                // 2. 获取用户宠物年龄总得分及标签
                Map<String, Double> userAgeScores = userPetAgeTotalScores.getOrDefault(userId, new HashMap<>());
                // 转换年龄得分格式（拆分宠物类型和年龄阶段）
                Map<String, Map<String, Double>> userPetAgeScores = new HashMap<>();
                for (Map.Entry<String, Double> entry : userAgeScores.entrySet()) {
                    String[] petAge = entry.getKey().split("-", 2);
                    if (petAge.length == 2) {
                        String pet = petAge[0];
                        String age = petAge[1];
                        userPetAgeScores.computeIfAbsent(pet, k -> new HashMap<>());
                        userPetAgeScores.get(pet).put(age, entry.getValue());
                    }
                }
                List<String> petAgeTags = determinePetAgeTags(userPetAgeScores);
                // 格式化年龄得分（宠物类型-年龄阶段:得分）
                String petAgeScoreStr = userAgeScores.entrySet().stream()
                        .map(entry -> String.format("%s:%.2f", entry.getKey(), entry.getValue()))
                        .reduce((a, b) -> a + "|" + b)
                        .orElse("");
                // 格式化年龄标签（逗号分隔）
                String petAgeTagStr = String.join(",", petAgeTags);

                // 3. 写入CSV行数据
                writer.write(String.format(
                        "%s,%s,%s,%s,%s,%d,%.2f,%.2f,%.2f,%s,%s,%s,%s\n",
                        record.get("user_id"),
                        record.get("behavior_type"),
                        record.get("behavior_time"),
                        record.get("product_category"),
                        record.get("product_title"),
                        record.get("base_behavior_weight"),
                        record.get("time_decay_factor"),
                        record.get("repeat_purchase_decay"),
                        record.get("final_behavior_weight"),
                        petTypeScoreStr,
                        petTypeTagStr,
                        petAgeScoreStr,
                        petAgeTagStr
                ));
            }

            System.out.println("达摩盘宠物特征数据生成完成！");
            System.out.printf("生成数据条数：%d条%n", numRecords);
            System.out.printf("输出文件路径：%s%n", csvFilePath);
            System.out.printf("数据时间窗口：近%d天（基准时间：2025-05-01）%n", TIME_WINDOW_DAYS);
        } catch (IOException e) {
            System.err.println("数据生成失败：" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 主函数：程序入口
     * @param args 命令行参数（无）
     */
    public static void main(String[] args) {
        // 生成10万条数据（符合工单验收标准：csv格式10万条以下）
        int numRecords = 10;
        String csvFilePath = "达摩盘宠物特征数据.csv";
        generateDmpPetFeatureData(numRecords, csvFilePath);
    }
}